home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / faxd / UUCPLock.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  6KB  |  281 lines

  1. /*    $Header: /usr/people/sam/fax/faxd/RCS/UUCPLock.c++,v 1.25 1994/04/11 16:31:51 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include <stdlib.h>
  26. #include <sys/param.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <signal.h>
  30. #include <string.h>
  31. #include <fcntl.h>
  32. #include <errno.h>
  33. #include <time.h>
  34. #include <pwd.h>
  35. #ifdef svr4
  36. extern "C" {
  37. #include <sys/mkdev.h>
  38. }
  39. #endif
  40.  
  41. #include "UUCPLock.h"
  42. #include "config.h"
  43.  
  44. /*
  45.  * UUCP Device Locking Support.
  46.  */
  47.  
  48. extern    void fxFatal(const char* va_alist ...);
  49.  
  50. UUCPLock::UUCPLock(const char* device)
  51. {
  52.     setupIDs();
  53.     char pathname[1024];
  54. #ifdef svr4
  55.     struct stat sb;
  56.     (void) stat(device, &sb);
  57.     sprintf(pathname, "%s/%s%03d.%03d.%03d", UUCP_LOCKDIR, UUCP_LOCKPREFIX,
  58.     major(sb.st_dev), major(sb.st_rdev), minor(sb.st_rdev));
  59. #else
  60.     const char* cp = strrchr(device, '/');
  61.     sprintf(pathname, "%s/%s%s", UUCP_LOCKDIR, UUCP_LOCKPREFIX,
  62.     cp ? cp+1 : device);
  63. #endif
  64.     file = pathname;
  65.     locked = FALSE;
  66. }
  67.  
  68. UUCPLock::~UUCPLock()
  69. {
  70.     unlock();
  71. }
  72.  
  73. uid_t UUCPLock::UUCPuid = (uid_t) -1;
  74. gid_t UUCPLock::UUCPgid = (gid_t) -1;
  75.  
  76. void
  77. UUCPLock::setupIDs()
  78. {
  79.     if (UUCPuid == (uid_t) -1) {
  80.     passwd *pwd = getpwnam("uucp");
  81.     if (!pwd)
  82.         fxFatal("Can not deduce identity of UUCP");
  83.     UUCPuid = pwd->pw_uid;
  84.     UUCPgid = pwd->pw_gid;
  85.     endpwent();            // paranoia
  86.     }
  87. }
  88. uid_t UUCPLock::getUUCPUid() { setupIDs(); return UUCPuid; }
  89. gid_t UUCPLock::getUUCPGid() { setupIDs(); return UUCPgid; }
  90.  
  91. time_t UUCPLock::lockTimeout = UUCP_LCKTIMEOUT;
  92. void UUCPLock::setLockTimeout(time_t t) { lockTimeout = t; }
  93.  
  94. /*
  95.  * Create a lock file.
  96.  */
  97. fxBool
  98. UUCPLock::create()
  99. {    
  100.     /*
  101.      * We create a separate file and link it to
  102.      * the destination to avoid a race condition.
  103.      */
  104.     fxStr tmpS(UUCP_LOCKDIR);
  105.     tmpS.append("/TM.faxXXXXXX");
  106.     char* tmp = tmpS;            // NB: for systems w/o prototypes
  107.     int fd = mkstemp(tmp);
  108.     if (fd >= 0) {
  109.     (void) writeData(fd);
  110. #if HAS_FCHMOD
  111.     (void) fchmod(fd, UUCP_LOCKMODE);
  112. #else
  113.     (void) chmod(tmp, UUCP_LOCKMODE);
  114. #endif
  115. #if HAS_FCHOWN
  116.     (void) fchown(fd, UUCPuid, UUCPgid);
  117. #else
  118.     (void) chown(tmp, UUCPuid, UUCPgid);
  119. #endif
  120.     (void) close(fd);
  121.  
  122.     locked = (link(tmp, (char*) file) == 0);
  123.     (void) unlink(tmp);
  124.     }
  125.     return (locked);
  126. }
  127.  
  128. /*
  129.  * Check if the lock file is
  130.  * newer than the specified age.
  131.  */
  132. fxBool
  133. UUCPLock::isNewer(time_t age)
  134. {
  135.     struct stat sb;
  136.     if (stat((char*) file, &sb) != 0)
  137.     return (FALSE);
  138.     return ((time(0) - sb.st_ctime) < age);
  139. }
  140.  
  141. /*
  142.  * Create a lock file.  If one already exists, the create
  143.  * time is checked for older than the age time (atime).
  144.  * If it is older, an attempt is made to unlink it and
  145.  * create a new one.
  146.  */
  147. fxBool
  148. UUCPLock::lock()
  149. {
  150.     if (locked)
  151.     return (FALSE);
  152.     uid_t ouid = geteuid();
  153.     seteuid(0);                // need to be root
  154.     fxBool ok = create();
  155.     if (!ok)
  156.     ok = check() && create();
  157.     seteuid(ouid);
  158.     return (ok);
  159. }
  160.  
  161. /*
  162.  * Unlock the device.
  163.  */
  164. void
  165. UUCPLock::unlock()
  166. {
  167.     if (locked) {
  168.     uid_t ouid = geteuid();
  169.     seteuid(0);            // need to be root
  170.     (void) unlink((char*) file);
  171.     seteuid(ouid);
  172.     locked = FALSE;
  173.     }
  174. }
  175.  
  176. /*
  177.  * Check if the owning process exists.
  178.  */
  179. fxBool
  180. UUCPLock::ownerExists(int fd)
  181. {
  182.     pid_t pid;
  183.     return readData(fd, pid) && (kill(pid, 0) == 0 || errno != ESRCH);
  184. }
  185.  
  186. /*
  187.  * Check to see if the lock exists and is still active.
  188.  * Locks are automatically expired after UUCPLock::lockTimeout seconds,
  189.  * or if the process owner is no longer around.
  190.  */
  191. fxBool
  192. UUCPLock::check()
  193. {
  194.     int fd = open((char*) file, O_RDONLY);
  195.     if (fd != -1) {
  196.     if (lockTimeout > 0) {
  197.         if (isNewer(lockTimeout) && ownerExists(fd)) {
  198.         close(fd);
  199.         return (FALSE);
  200.         }
  201.         close(fd);
  202.         return (unlink((char*) file) == 0);
  203.     } else {
  204.         close(fd);
  205.         return (FALSE);
  206.     }
  207.     }
  208.     return (TRUE);
  209. }
  210.  
  211. /*
  212.  * ASCII lock file interface.
  213.  */
  214. AsciiUUCPLock::AsciiUUCPLock(const char* device) : UUCPLock(device),
  215.     data(UUCP_PIDDIGITS+2)
  216. {
  217.     sprintf((char*) data, "%*d\n", UUCP_PIDDIGITS, getpid());
  218. }
  219.  
  220. AsciiUUCPLock::~AsciiUUCPLock()
  221. {
  222. }
  223.  
  224. fxBool
  225. AsciiUUCPLock::writeData(int fd)
  226. {
  227.     return write(fd, (char*) data, UUCP_PIDDIGITS+1) == (UUCP_PIDDIGITS+1);
  228. }
  229.  
  230. fxBool
  231. AsciiUUCPLock::readData(int fd, pid_t& pid)
  232. {
  233.     char buf[UUCP_PIDDIGITS+1];
  234.     if (read(fd, buf, UUCP_PIDDIGITS) == UUCP_PIDDIGITS) {
  235.     buf[UUCP_PIDDIGITS] = '\0';
  236.     pid = atoi(buf);
  237.     return (TRUE);
  238.     } else
  239.     return (FALSE);
  240. }
  241.  
  242. /*
  243.  * Binary lock file interface.
  244.  */
  245.  
  246. BinaryUUCPLock::BinaryUUCPLock(const char* device) : UUCPLock(device)
  247. {
  248.     data = getpid();        // binary pid of lock holder
  249. }
  250.  
  251. BinaryUUCPLock::~BinaryUUCPLock()
  252. {
  253. }
  254.  
  255. fxBool
  256. BinaryUUCPLock::writeData(int fd)
  257. {
  258.     return write(fd, (char*) &data, sizeof (data)) == sizeof (data);
  259. }
  260.  
  261. fxBool
  262. BinaryUUCPLock::readData(int fd, pid_t& pid)
  263. {
  264.     int data;
  265.     if (read(fd, (char*) &data, sizeof (data)) == sizeof (data)) {
  266.     pid = data;
  267.     return (TRUE);
  268.     } else
  269.     return (FALSE);
  270. }
  271.  
  272. UUCPLock*
  273. OSnewUUCPLock(const char* device)
  274. {
  275. #if UUCP_LOCKTYPE == 1
  276.     return new BinaryUUCPLock(device);
  277. #else
  278.     return new AsciiUUCPLock(device);
  279. #endif
  280. }
  281.